/*
 * Copyright 2007 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.sockets.client.impl;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.sockets.client.BinarySocket;
import com.google.gwt.sockets.client.SocketException;
import com.google.gwt.sockets.client.SocketListener;
import com.google.gwt.sockets.client.SocketsFactory;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RootPanel;

/**
 * <p>The Flash-based implementation of binary sockets. It uses Flash Applet as proxy to obtain necessary
 * socket funactionality.</p>
 *
 * <p>You should use methods of {@link com.google.gwt.sockets.client.SocketsFactory SocketsFactory} to 
 * create instances of binary sockets. Use this class directly only for specific purposes.</p>
 *
 * @see com.google.gwt.sockets.client.BinarySocket
 * @see com.google.gwt.sockets.client.SocketsFactory
 * @author Aleksey Lagoshin
 */
public class FlashBinarySocketImpl extends BinarySocket {

  private static final String TAG =
          "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' id='{0}' width='0px' height='0px'>" +
          "  <param name='movie' value='flashbinary.swf'>" +
          "  <param name='play' value='false'>" +
          "  <param name='loop' value='false'>" +
          "  <param name='allowScriptAccess' value='always'/>" +
          "  <param name='FlashVars' value='crossdomain={1}&id={2}'/>" +
          "  <embed" +
          "          name='{0}'" +
          "          src='flashbinary.swf'" +
          "          width='0px'" +
          "          height='0px'" +
          "          play='false'" +
          "          loop='false'" +
          "          swLiveConnect='true'" +
          "          allowScriptAccess='always'" +
          "          FlashVars='crossdomain={1}&id={2}'" +
          "  </embed>" +
          "</object>";

  private HTML flashTag;

  private String appletName;

  /**
   * URL to crossdomain policy file.
   */
  private String crossdomain = "";

  /**
   * Standart constructor for socket classes.
   *
   * @param listener a listener for the socket
   */
  public FlashBinarySocketImpl(SocketListener listener) {
    super(listener);
  }

  /**
   * <p>Constructor with additional parameter for URL to crossdomain policy file.</p>
   *
   * <p>More information about crossdomain policy file you can read in comments of
   * {@link com.google.gwt.sockets.client.SocketsFactory SocketsFactory} class.</p>
   *
   * @param listener a listener for the socket
   * @param crossdomain URL to crossdomain policy file, if it is null Flash will download a
   * default crossdomain policy file from the server where this GWT application is located; the
   * default policy file allows Flash to connect to the server where this GWT application is located on
   * ports 1024 and later
   */
  public FlashBinarySocketImpl(SocketListener listener, String crossdomain) {
    this.crossdomain = crossdomain != null ? crossdomain : SocketsFactory.getDefaultPolicyFile();
    initialize(listener);
  }

  protected void initImplementation(int id) {
    appletName = "flashbinApp_" + id;
    flashTag = new HTML();
    flashTag.setSize("0", "0");

    // flashTag.setHTML command MUST be after adding that tag to a page, otherwise Flash Applet won't work
    // correctly on IE
    RootPanel.get().add(flashTag);
    flashTag.setHTML(TAG.replaceAll("[{]0[}]", appletName).replaceAll("[{]1[}]", crossdomain).replaceAll("[{]2[}]", String.valueOf(id)));
  }

  public void shutdown() throws SocketException {
    checkSocket();
    super.shutdown();
    RootPanel.get().remove(flashTag);
  }

  /**
   * Loads crossdomain policy file from specified URL.
   *
   * @param url URL to crossdomain policy file
   * @throws SocketException raised if socket is not ready
   */
  public void loadPolicyFile(String url) throws SocketException {
    checkSocket();
    loadPolicyFileImpl(url);
  }

  /**
   * Flash cannot return the link on itself, so we need to find the applet object manually.
   *
   * @param socketObj is null here
   */
  protected void onReady(JavaScriptObject socketObj) {
    super.onReady(findApplet());
  }

  /**
   * Finds the applet object.
   *
   * @return the applet object
   */
  private native JavaScriptObject findApplet() /*-{
    return $doc[this.@com.google.gwt.sockets.client.impl.FlashBinarySocketImpl::appletName];
  }-*/;

  private native void loadPolicyFileImpl(String url)/*-{
    this.@com.google.gwt.sockets.client.AbstractSocket::socketObj.loadPolicyFile(url);
  }-*/;

  protected String getPrefix() {
    return "flashbin_";
  }

}